package com.cndw.kungfu.model.goods;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.cndw.kungfu.config.ConstantsRadio;
import com.cndw.kungfu.domain.Goods;
import com.cndw.kungfu.domain.GoodsMode;
import com.cndw.kungfu.ext.LogUtil;
import com.cndw.kungfu.model.Context;
import com.cndw.kungfu.model.goods.domain.GoodsComparator;

/**
 * 玩家的背包
 * 
 * @author fantadust
 * 
 */
public class PlayerBoxs {
	private final long playerId;
	private int boxsGirds = 36;
	private int holdGrids = 36;

	public static final int PlayerUsedKey = 1;
	/**
	 * 任务物品的起始格子
	 */
	public static final int TaskSpiltNum = 109;

	public static final int typeBox = 0;
	public static final int typeHold = 1;
	public static final int typeEquip = 2;
	/**
	 * 任务品的个数
	 */
	private int taskItemNums = 0;

	/**
	 * 物品列表
	 */
	private Map<Integer, Goods> boxsMap = new ConcurrentHashMap<Integer, Goods>();
	private Map<Integer, Goods> holdMap = new HashMap<Integer, Goods>();
	private Map<Integer, Goods> equipMap = new HashMap<Integer, Goods>(10);

	/**
	 * 摆摊位置记录
	 */
	private Set<Integer> lockGoodsSet = new HashSet<Integer>();

	public PlayerBoxs(long playerId, List<Goods> goods, int boxsGirds, int holdGrids) {
		this.playerId = playerId;
		this.boxsGirds = boxsGirds;
		this.holdGrids = holdGrids;
		initBoxs(goods);
	}

	private void initBoxs(List<Goods> goods) {
		List<Goods> faildGoodsList = new ArrayList<Goods>();
		for (Goods e : goods) {
			e.setHashcodeKey(e.hashCode());
			switch (e.getStorageType()) {
			case typeBox:
				if (e.getStoragePlace() >= TaskSpiltNum) {
					taskItemNums++;
				}
				if (boxsMap.containsKey(e.getStoragePlace())) {
					Goods failedGoods = boxsMap.get(e.getStoragePlace());
					faildGoodsList.add(failedGoods);
					LogUtil.getSysErr().error("goods init err  on" + failedGoods.info());
				}
				boxsMap.put(e.getStoragePlace(), e);
				break;
			case typeHold:
				holdMap.put(e.getStoragePlace(), e);
				break;
			case typeEquip:
				equipMap.put(e.getPosition(), e);
				break;
			}
		}
		if (!faildGoodsList.isEmpty()) {
			for (Goods e : faildGoodsList) {
				for (int i = 1; i <= 142; i++) {
					if (!boxsMap.containsKey(i)) {
						e.setStorageType(0);
						e.setStoragePlace(i);
						e.commitSync();
						boxsMap.put(e.getStoragePlace(), e);
						LogUtil.getSysErr().error("goods auto fixed " + e.info());
						break;
					}	
				}	
			}
		}

	}

	/**
	 * 返回格子数
	 * 
	 * @param storageType
	 * @return
	 */
	public synchronized int getMaxGirds(int storageType) {
		if (storageType == typeHold) {
			return holdGrids;
		} else {
			return boxsGirds;
		}
	}

	/**
	 * 格子数管理
	 * 
	 * @param storageType
	 * @param num
	 * @return
	 */
	public synchronized void activationGirds(int boxsOpen, int holdOpen) {
		if (boxsOpen > 0) {
			boxsGirds = boxsOpen;
		}
		if (holdOpen > 0) {
			holdGrids = holdOpen;
		}
	}

	public boolean checkBlack() {
		return checkBlack(1);
	}

	/**
	 * 返回是否够格子存物品
	 * 
	 * @param num
	 * @return
	 */
	public synchronized boolean checkBlack(int num) {
		if (num == 0) {
			return true;
		}
		return getBlackNumbers() >= num;
	}

	public synchronized int getBlackNumbers() {
		return getMaxGirds(typeBox) - (boxsMap.size() - taskItemNums);
	}

	/**
	 * 获取空格
	 * 
	 * @param targerType
	 * @return
	 */
	public synchronized int getBlack(int storageType, boolean isTaskItem) {
		Map<Integer, Goods> dataMap = getStorageMap(storageType);
		int startGirds = 1;
		int maxGirds = getMaxGirds(storageType);
		if (isTaskItem && storageType == typeBox) {
			startGirds = TaskSpiltNum;
			maxGirds = 144;
		}

		for (int i = startGirds; i <= maxGirds; i++) {
			if (!dataMap.containsKey(i)) {
				return i;
			}
		}
		return 0;
	}

	/**
	 * 某个位置是否有物品
	 * 
	 * @param storagePlace
	 * @return
	 */
	public synchronized boolean containsKey(int storagePlace) {

		// 忽略锁定物品
		if (lockGoodsSet.contains(storagePlace)) {
			return false;
		}

		return boxsMap.containsKey(storagePlace);
	}

	/**
	 * 按背包总存储id,获取物品
	 * 
	 * @param storagePlace
	 * @return
	 */
	public synchronized Goods get(int storagePlace) {

		// 忽略锁定物品
		if (lockGoodsSet.contains(storagePlace)) {
			return null;
		}

		return boxsMap.get(storagePlace);
	}

	/**
	 * 按背包总存储id,获取物品(只在摆摊的代码中使用)
	 * 
	 * @param storagePlace
	 * @return
	 */
	public synchronized Goods getByLock(int storagePlace) {
		return boxsMap.get(storagePlace);
	}

	public synchronized Goods getBySearcheId(long id) {
		for (Goods e : boxsMap.values()) {
			if (e.getId() == id) {
				return e;
			}
		}
		for (Goods e : equipMap.values()) {
			if (e.getId() == id) {
				return e;
			}
		}
		for (Goods e : holdMap.values()) {
			if (e.getId() == id) {
				return e;
			}
		}
		return null;
	}

	public synchronized Goods getBySearcheGoodsId(int goodsId) {
		for (Goods e : boxsMap.values()) {
			if (e.getGoodsId() == goodsId) {
				return e;
			}
		}
		for (Goods e : equipMap.values()) {
			if (e.getGoodsId() == goodsId) {
				return e;
			}
		}
		for (Goods e : holdMap.values()) {
			if (e.getGoodsId() == goodsId) {
				return e;
			}
		}
		return null;
	}

	/**
	 * 删除某个背包位置的物品
	 * 
	 * @param storagePlace
	 * @return
	 */
	public Goods remove(int storagePlace) {
		return remove(storagePlace, false);
	}

	public synchronized Goods remove(int storagePlace, boolean silent) {
		Goods goods = boxsMap.remove(storagePlace);
		if (goods != null) {
			goods.alertStackNum(-goods.getStackNum(), silent);
			goods.setStackNum(0);// 防止意外数量非为0
			if (storagePlace >= TaskSpiltNum) {
				taskItemNums--;
			}
		} else {
			LogUtil.getMain().debug("playerboxs remove err " + storagePlace + " " + playerId);
			new Throwable("err remove ").printStackTrace();
		}
		return goods;
	}

	public synchronized int add(Goods goods) {
		return add(goods, false);
	}

	/**
	 * 添加物品,没有位置id时候.则给一个新的位置
	 * 
	 * @param goods
	 */
	public synchronized int add(Goods goods, boolean silent) {
		if (goods == null) {
			return 0;
		}
		int storagePlace = goods.getStoragePlace();
		if (storagePlace == 0) {
			storagePlace = getBlack(typeBox, goods.getGoodsMode().isTaskItem());
			goods.setStoragePlace(storagePlace);
			if (storagePlace >= TaskSpiltNum) {
				taskItemNums++;
			}
		}
		if (storagePlace <= 0) {
			LogUtil.getMain().error("add goods err storagePlace " + goods.info());
			new Throwable("pay goods err id:" + playerId + " err add  ").printStackTrace();
			return 0;// 没有位置是0的存储空间
		}
		if (boxsMap.containsKey(storagePlace)) {
			LogUtil.getMain().error("err storagePlace havaed " + goods.info());
		}
		boxsMap.put(storagePlace, goods);
		if (!silent) {
			Context.getTcpServer().broadcast(goods.toGoodsVO(), ConstantsRadio.boxGot, playerId);
		}
		goods.commitSync();// 新增的提交同步

		return storagePlace;
	}

	/**
	 * 获取位置列表
	 * 
	 * @param position
	 * @return
	 */
	public synchronized Goods getByPostition(int position) {
		return equipMap.get(position);
	}

	/**
	 * 返回背包的所有物品
	 * 
	 * @return
	 */
	public synchronized Collection<Goods> getBoxsGoods() {
		return boxsMap.values();
	}

	/**
	 * 获取身上装备列表
	 * 
	 * @return
	 */
	public synchronized Collection<Goods> getEquipList() {
		return equipMap.values();
	}

	/**
	 * 获取仓库的物品
	 * 
	 * @return
	 */
	public synchronized Collection<Goods> getHoldGoods() {
		return holdMap.values();
	}

	/**
	 * 返回我的所有物品.
	 * 
	 * @return
	 */
	public synchronized List<Goods> getAllGoods() {
		List<Goods> allGoods = new ArrayList<Goods>();
		allGoods.addAll(boxsMap.values());
		allGoods.addAll(equipMap.values());
		allGoods.addAll(holdMap.values());
		return allGoods;

	}

	/**
	 * 获取某个物品数量
	 * 
	 * @param goodsId
	 * @return
	 */
	public synchronized int getStackNum(int goodsId) {
		int goodsStackNum = 0;
		for (Goods e : boxsMap.values()) {
			if (e.getGoodsId() == goodsId && !lockGoodsSet.contains(e.getStoragePlace())) {
				goodsStackNum += e.getStackNum();
			}
		}
		return goodsStackNum;
	}

	public boolean isHaveGoods(int goodsId) {
		return getStackNum(goodsId) >= 1;
	}

	/**
	 * 消费掉某个物品
	 * 
	 * @param goodsId
	 * @param costNum
	 * @return
	 */
	public int costGoods(int goodsId, int costNum) {
		return costGoodsSilent(goodsId, costNum, false);
	}

	public synchronized int costGoodsSilent(int goodsId, int costNum, boolean silent) {
		int tempCost = 0;
		int bindType = 0;
		for (Goods e : boxsMap.values()) {
			// 忽略锁定物品
			if (e.getGoodsId() == goodsId && !lockGoodsSet.contains(e.getStoragePlace())) {
				if (e.getBinding() > 0) {
					bindType = 1;
				}
				if (costNum < e.getStackNum()) {
					tempCost = costNum;
					e.alertStackNum(-tempCost, silent);
					break;
				} else {
					tempCost = e.getStackNum();
					remove(e.getStoragePlace(), silent);
				}
				costNum = costNum - tempCost;
				if (costNum <= 0) {
					break;
				}
			}
		}
		return bindType;
	}

	/**
	 * 把装备穿上
	 * 
	 * @param goods
	 */
	public synchronized void execWearing(Goods goods) {
		int position = goods.getPosition();
		Goods oldEquip = equipMap.get(position);
		boxsMap.remove(goods.getStoragePlace());
		Map<String, Object> map = new HashMap<String, Object>();

		map.put("storagePlace", goods.getStoragePlace());
		map.put("stackNum", 0);
		Context.getTcpServer().broadcast(map, ConstantsRadio.boxChange, playerId);

		if (oldEquip != null) {
			execDisplay(oldEquip);
		}
		goods.setStorageType(typeEquip);
		goods.setStoragePlace(0);
		equipMap.put(position, goods);

	}

	/**
	 * 把装备脱下.显示在背包
	 * 
	 * @param storagePlace
	 */
	public synchronized void execDisplay(Goods oldEquip) {
		if (oldEquip == null || oldEquip.getStorageType() == typeBox) {
			return;
		}
		equipMap.remove(oldEquip.getPosition());
		oldEquip.setUseNo(0);
		oldEquip.setPosition(0);
		oldEquip.setStorageType(typeBox);
		oldEquip.setStoragePlace(0);

		add(oldEquip);
	}

	/**
	 * 整理包裹
	 * 
	 * @param type
	 */
	public synchronized void classify(int type) {
		Map<Integer, Goods> dataMap = getStorageMap(type);
		List<Goods> tempList = new ArrayList<Goods>(dataMap.values());
		Map<Integer, List<Goods>> tmpNeedMerger = new HashMap<Integer, List<Goods>>();
		for (Goods e : tempList) {
			if (e.getGoodsMode() == null) {
				continue;
			}
			if (e.getStackNum() < e.getGoodsMode().getMaxStack()) {
				if (tmpNeedMerger.containsKey(e.getGoodsId()) == false) {
					tmpNeedMerger.put(e.getGoodsId(), new ArrayList<Goods>());
				}
				tmpNeedMerger.get(e.getGoodsId()).add(e);
			}
		}
		for (List<Goods> mergerList : tmpNeedMerger.values()) {
			if (mergerList.size() > 1) {

				int nowTarget = 0;
				int bindNowTarget = 0;
				int maxTarget = mergerList.size();
				for (int i = maxTarget - 1; i > 0; i--) {
					Goods aGoods = mergerList.get(i);
					int currentTarget = nowTarget;
					if (aGoods.getBinding() > 0) {
						currentTarget = bindNowTarget;
					}
					if (currentTarget >= i) {
						continue;
					}
					GoodsMode goodsMode = aGoods.getGoodsMode();
					for (int j = currentTarget; j < i; j++) {
						Goods tGoods = mergerList.get(j);
						if (tGoods.getStackNum() >= goodsMode.getMaxStack() || aGoods.getBinding() != tGoods.getBinding()) {
							continue;
						}
						int aAlert = aGoods.getStackNum();
						if (aGoods.getStackNum() + tGoods.getStackNum() > goodsMode.getMaxStack()) {
							aAlert = goodsMode.getMaxStack() - tGoods.getStackNum();
						}
						aGoods.alertStackNum(-aAlert, true);
						tGoods.alertStackNum(aAlert, true);
						if (aGoods.getBinding() > 0) {
							bindNowTarget = j;
						} else {
							nowTarget = j;
						}
						if (aGoods.getStackNum() == 0) {
							break;
						}
					}

				}

			}
		}

		dataMap.clear();
		GoodsComparator c = new GoodsComparator();
		Collections.sort(tempList, c);
		int boxkey = 0, taskKey = TaskSpiltNum - 1, tmpKey = 0;
		for (Goods e : tempList) {
			if (e.getGoodsMode() == null || e.getStackNum() <= 0) {
				continue;
			}
			if (e.getGoodsMode().isTaskItem()) {
				taskKey++;
				tmpKey = taskKey;
			} else {
				boxkey++;
				tmpKey = boxkey;
			}
			if (e.getStoragePlace() != tmpKey) {
				e.setStoragePlace(tmpKey);
				e.commitSync();
			}

			e.setStoragePlace(tmpKey);

			dataMap.put(tmpKey, e);
		}

	}

	private Map<Integer, Goods> getStorageMap(int type) {

		switch (type) {
		case typeBox:
			return boxsMap;
		case typeHold:
			return holdMap;
		case typeEquip:
			return equipMap;
		}
		return null;
	}

	/**
	 * 物品进行移动
	 * 
	 * @param sourceType
	 * @param sourcePlace
	 * @param targerType
	 * @param targerPlace
	 * @return
	 */
	public synchronized int moveStoragerPlace(int sourceType, int sourcePlace, int targerType, int targerPlace) {
		int finalTargerPlace = 0;
		if (sourceType == typeEquip) {// 身上的装备不允许拖动
			return 0;
		}
		if (sourceType == targerType && sourcePlace == targerPlace) {
			return 0;
		} else if (sourcePlace <= 0) {
			return 0;
		} else if (targerType == typeBox && targerPlace > boxsGirds) {
			return 0;
		} else if (targerType == typeHold && targerPlace > holdGrids) {
			return 0;
		}

		Map<Integer, Goods> sourceDataMap = getStorageMap(sourceType);
		Goods sourceGoods = sourceDataMap.get(sourcePlace);
		if (sourceGoods == null) {
			return 0;
		} else if (sourceGoods.getGoodsMode().isTaskItem()) {// 任务品不允许拖动
			return 0;
		}

		Map<Integer, Goods> targerDataMap = getStorageMap(targerType);
		Goods targerGoods = targerDataMap.get(targerPlace);
		if (targerGoods == null && targerPlace <= 0) {
			targerPlace = getBlack(targerType, false);
			if (targerPlace <= 0) {
				return finalTargerPlace;
			}
		} else if (targerGoods != null && sourceType != targerType) {
			return finalTargerPlace;// 不是同类型存储,不允许交替位置
		}
		sourceDataMap.remove(sourcePlace);// 清理自己位置的物品
		if (targerGoods != null) {
			targerGoods.setStoragePlace(sourcePlace);
			targerGoods.setStorageType(sourceType);
			sourceDataMap.put(sourcePlace, targerGoods);
			targerGoods.commitSync();
		}

		sourceGoods.setStoragePlace(targerPlace);
		sourceGoods.setStorageType(targerType);
		sourceGoods.commitSync();
		targerDataMap.put(targerPlace, sourceGoods);// 可能是覆盖,可能是新增
		finalTargerPlace = targerPlace;
		return finalTargerPlace;
	}

	/**
	 * 锁定物品
	 * 
	 * @param storage
	 */
	public synchronized void lockGoods(int storage) {
		lockGoodsSet.add(storage);
	}

	/**
	 * 解锁物品
	 * 
	 * @param storage
	 */
	public synchronized void unlockGoods(int storage) {
		lockGoodsSet.remove(storage);
	}

	/**
	 * 判断是否锁定
	 * 
	 * @param storage
	 * @return
	 */
	public synchronized boolean isLocked(int storage) {
		return lockGoodsSet.contains(storage);
	}

	/**
	 * 获取所有锁定物品
	 * 
	 * @return
	 */
	public Set<Integer> getLockGoods() {
		return lockGoodsSet;
	}
}
